package com.acme.bankapp.domain.bank;

import com.acme.bankapp.domain.bank.exception.AccountAlreadyAssignedException;
import com.acme.bankapp.domain.bank.exception.NotEnoughFundsException;

@SuppressWarnings("serial")
public abstract class AbstractAccount implements Account {
	protected Client client = null;
	protected double balance;
	private String uuid;

	/**
	 * Creates an account.
	 * 
	 * @param amount
	 *            initial amount of funds, must be positive
	 */
	public AbstractAccount(final double amount) {
		if (amount < 0) {
			throw new IllegalArgumentException(
					"Initial amount of funds cannot be negative.");
		}
		this.balance = amount;
	}

	/**
	 * @inheritDoc
	 */
	public double getBalance() {
		return balance;
	}

	/**
	 * @inheritDoc
	 */
	public void deposit(final double amount) {
		if (amount > 0) {
			balance += amount;
		} else {
			throw new IllegalArgumentException(
					"Amount of funds to deposit must be positive.");
		}
	}

	/**
	 * @inheritDoc
	 */
	public void withdraw(final double amount) throws NotEnoughFundsException {
		if (amount > 0) {
			if (balance >= amount) {
				balance -= amount;
			} else {
				throw new NotEnoughFundsException(amount - balance);
			}
		} else {
			throw new IllegalArgumentException(
					"Amount of funds to withdraw must be positive.");
		}
	}

	/**
	 * @inheritDoc
	 */
	public double maximumAmountToWithdraw() {
		return balance;
	}

	/**
	 * {@inheritDoc}
	 */
	public Client getClient() {
		return client;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @throws AccountAlreadyAssignedException
	 */
	public void assignToClient(Client client, String uuid)
			throws AccountAlreadyAssignedException {
		if (this.client == null) {
			this.client = client;
			this.uuid = uuid;
		} else {
			throw new AccountAlreadyAssignedException();
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	public String getUUID() {
		return uuid;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((client == null) ? 0 : client.hashCode());
		result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AbstractAccount other = (AbstractAccount) obj;
		if (client == null) {
			if (other.client != null)
				return false;
		} else if (!client.equals(other.client))
			return false;
		if (uuid == null) {
			if (other.uuid != null)
				return false;
		} else if (!uuid.equals(other.uuid))
			return false;
		return true;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	public long decimalValue() {
		return Math.round(getBalance());
	}
}
